package cloud.health.framework.computing.core;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;

@Slf4j
public abstract class AbstractNettyClient {

    private Bootstrap bootstrap;
    private NioEventLoopGroup eventExecutors;
    private ChannelFuture future;

    /**
     * 运行
     */
    public boolean run() {
        this.eventExecutors = new NioEventLoopGroup();
        // 创建bootstrap对象，配置参数
        this.bootstrap = new Bootstrap();
        // 设置线程组
        bootstrap.group(eventExecutors)
                // 设置客户端的通道实现类型
                .channel(NioSocketChannel.class)
                // keepalive
                .option(ChannelOption.SO_KEEPALIVE, true)
                // .option(ChannelOption.SO_REUSEADDR, true)
                // 使用匿名内部类初始化通道
                .handler(this.channelInitializer());
        try {
            future = this.bootstrap.connect(hostname(), port()).sync();
            log.info("客户端连接{}:{}成功， future = {}", hostname(), port(), future);
            return true;
        } catch (InterruptedException e) {
            log.error("客户端连接{}:{}服务器失败 --> \n", hostname(), port(), e);
        }
        return false;
    }

    /**
     * 释放
     */
    @Override
    protected void finalize() throws Throwable {
        this.stop();
        super.finalize();
    }

    /**
     * 停止
     */
    public void stop() {
        if (Objects.nonNull(future)) {
            this.future.channel().close();
        }
        if (Objects.nonNull(this.eventExecutors)) {
            this.eventExecutors.shutdownGracefully();
        }
        if (Objects.nonNull(this.bootstrap)) {
            this.bootstrap = null;
        }
        log.info("client is stop, port = {} future = {}", port(), future);
    }

    /**
     * 设置服务器地址
     */
    protected abstract String hostname();

    /**
     * 设置服务器端口
     */
    protected abstract int port();

    /**
     * 获取管道配置
     */
    protected abstract ChannelInitializer<SocketChannel> channelInitializer();

}
